package com.ultrasoft.farmasoft.repository;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.ultrasoft.farmasoft.domain.Bill;

@Repository(value = "billDao")
@Transactional(readOnly = false)
public class BillDaoImpl implements BillDao {

	private EntityManager em = null;
	@PersistenceContext
	public void setEntityManager(EntityManager em) {
		this.em = em;
	}
	public List<Bill> getListBill() {
		TypedQuery<Bill> q = em.createNamedQuery("Bill.findAll",Bill.class);
    	return q.getResultList();
	}

	public List<Bill> getListBillByPeriodId(Integer periodId) {
		TypedQuery<Bill> q = em.createNamedQuery("Bill.findByPeriodId",Bill.class);
    	q.setParameter("periodId",periodId);
    	return q.getResultList();
	}

	public List<Bill> getListBillByBillId(Integer billId) {
		TypedQuery<Bill> q = em.createNamedQuery("Bill.findByBillId",Bill.class);
    	q.setParameter("billId",billId);
    	return q.getResultList();
	}

	public Bill findBillByPeriodIdByBillId(Integer periodId,Integer billId) {
		Bill res= null;
    	Query q = em.createNamedQuery("Bill.findByPeriodIdByBillId");
    	q.setParameter("periodId",periodId);
    	q.setParameter("billId",billId);
    	if(q.getResultList().size() == 1 )
    		res=(Bill)q.getSingleResult();
    	return res;
	}

	public void remove(Bill bill) {
		em.remove(findBillByPeriodIdByBillId(bill.getBillPK().getPeriodId(),bill.getBillPK().getBillId()));
	}

	public void update(Bill bill) {
		em.merge(bill);
	}

	public void add(Bill bill) {
		em.persist(bill);
	}
	public Integer findBillIdIdMax(){
		Integer res = 0;
		if(getListBill().isEmpty())
			res = 1;
		else{
			res=(Integer)em.createNamedQuery("Bill.findBillIdIdMax").getSingleResult();
			res++;
		}
		return res;
	}
	
	 
	    public String getCodigoDeControl(long longNA,long longNF,long longCI,long longFT,double doubleMT,String LD){
	        String NA=Long.toString(longNA);
	        String NF=Long.toString(longNF);
	        String CI=Long.toString(longCI);
	        String FT=Long.toString(longFT);
	        String MT=Long.toString((long)round(doubleMT,0));
	  
	        // PASO 1
	        NF = NF + Verhoeff(NF);NF = NF + Verhoeff(NF);CI = CI + Verhoeff(CI);CI = CI + Verhoeff(CI);FT = FT + Verhoeff(FT);
	        FT = FT + Verhoeff(FT);MT = MT + Verhoeff(MT);MT = MT + Verhoeff(MT);
	        long SA = Long.parseLong(NF)+Long.parseLong(CI)+Long.parseLong(FT)+Long.parseLong(MT);
	        SA = (SA*10) + Verhoeff(SA+"");SA = (SA*10) + Verhoeff(SA+"");SA = (SA*10) + Verhoeff(SA+"");
	        SA = (SA*10) + Verhoeff(SA+"");SA = (SA*10) + Verhoeff(SA+"");
	        String strSA=Long.toString(SA);String DV=strSA.substring(strSA.length()-5,strSA.length());
	  
	        // PASO 2
	        int array[]=stringToArray(DV);
	        for(int i=0;i<array.length;i++){
	            array[i]=array[i]+1;
	        }
	        
	        String arrayCadena[]=new String[5];
	        int posini=0;
	        int posfin=0;
	        for(int i=0;i<array.length;i++){
	            if(i==0) posini=0;
	            else posini+=array[i-1];
	            posfin+=array[i];
	            arrayCadena[i]=LD.substring(posini,posfin);
	        }
	        String strNA=NA+arrayCadena[0];String strNF=NF+arrayCadena[1];String strCI=CI+arrayCadena[2];String strFT=FT+arrayCadena[3];String strMT=MT+arrayCadena[4];

	        // PASO 3
	        String cadenaConcatenada=strNA+strNF+strCI+strFT+strMT;
	        String llaveCifrado=LD+DV;
	        String resPaso3=arc4(cadenaConcatenada,llaveCifrado);
	  
	        // PASO 4
	        int parcial1[]={1,6,11,16,21};int parcial2[]={2,7,12,17,22};int parcial3[]={1,8,13,18,23};int parcial4[]={1,9,14,19,24};int parcial5[]={1,10,15,20,25};
	        int ST=0;
	        for(int i=0;i<resPaso3.length();i++){
	            int car=(int)resPaso3.charAt(i);
	            ST+=car;
	        }
	        int offset=5;int SP1=0;int index=1;
	        while(index<=resPaso3.length()){
	            int car=(int)resPaso3.charAt(index-1);
	            SP1+=car;
	            index+=offset;
	        }
	        int SP2=0;index=2;
	        while(index<=resPaso3.length()){
	            int car=(int)resPaso3.charAt(index-1);SP2+=car;index+=offset;
	        }
	        int SP3=0;index=3;
	        while(index<=resPaso3.length()){
	            int car=(int)resPaso3.charAt(index-1);SP3+=car;index+=offset;
	        }
	        int SP4=0;index=4;
	        while(index<=resPaso3.length()){
	            int car=(int)resPaso3.charAt(index-1);SP4+=car;index+=offset;
	        }
	        int SP5=0;index=5;
	        while(index<=resPaso3.length()){
	            int car=(int)resPaso3.charAt(index-1);SP5+=car;index+=offset;
	        }
	        
	        // PASO 5
	        int multi1=(ST*SP1)/array[0];int multi2=(ST*SP2)/array[1];int multi3=(ST*SP3)/array[2];int multi4=(ST*SP4)/array[3];int multi5=(ST*SP5)/array[4];int totalMulti=multi1+multi2+multi3+multi4+multi5;
	        String resPaso5=Base64(totalMulti);
	  
	        // PASO 6
	        String resPaso6=arc4(resPaso5,LD+DV);
	        return format(resPaso6);
	    }
	    public int[] intToArray(int num){
	        int res[]=new int[5];
	        for(int i=res.length-1;i>=0;i--){
	            int digito=num%10;num=num/10;res[i]=digito;
	        }
	        return res;
	    }
	    public int[] stringToArray(String num){
	        int res[]=new int[5];
	        for(int i=0;i<num.length();i++){
	            String digito=num.substring(i,i+1);res[i]=Integer.parseInt(digito);
	        }
	        return res;
	    }
	    public String format(String codigo){
	        String codigocontrol="";
	        int index=0;int posini=0;int posfin=0;
	        while(index<codigo.length()){
	            if(index==0)
	                posini=0;
	            else 
	                posini+=2;
	            posfin+=2;String par=codigo.substring(posini,posfin);codigocontrol+=par+"-";index+=2;
	        }
	        return codigocontrol.substring(0,codigocontrol.length()-1);
	    }
	    
	    public String Base64(int X ){
	        String base64_chr = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";int C = 0;String S = "";
	        if ( X < 0 )
	            return S;
	        // Convert Number to Base64
	        do {
	            C = X%64 ; S = base64_chr.charAt(C) + S ; X = (int) Math.floor(X/64);
	        } while(X!=0);
	        return S;
	    }
	    
	    public int Base10(String S) {
	        String base64_chr = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";int T = 0;
	        for (int J = 0 ; J < S.length() ; J++)
	            T = T*64 + base64_chr.indexOf(S.substring(J, 1));
	        return T ;
	    }
	    
	    public int Verhoeff(String code) {
	        int[][] D_TABLE = new int[][] {
	        {0,  1,  2,  3,  4,  5,  6,  7,  8,  9},
	        {1,  2,  3,  4,  0,  6,  7,  8,  9,  5},
	        {2,  3,  4,  0,  1,  7,  8,  9,  5,  6},
	        {3,  4,  0,  1,  2,  8,  9,  5,  6,  7},
	        {4,  0,  1,  2,  3,  9,  5,  6,  7,  8},
	        {5,  9,  8,  7,  6,  0,  4,  3,  2,  1},
	        {6,  5,  9,  8,  7,  1,  0,  4,  3,  2},
	        {7,  6,  5,  9,  8,  2,  1,  0,  4,  3},
	        {8,  7,  6,  5,  9,  3,  2,  1,  0,  4},
	        {9,  8,  7,  6,  5,  4,  3,  2,  1,  0}};
	        int[][] P_TABLE = new int[][] {
	        {0,  1,  2,  3,  4,  5,  6,  7,  8,  9},
	        {1,  5,  7,  6,  2,  8,  3,  0,  9,  4},
	        {5,  8,  0,  3,  7,  9,  6,  1,  4,  2},
	        {8,  9,  1,  6,  0,  4,  3,  5,  2,  7},
	        {9,  4,  5,  3,  1,  2,  6,  8,  7,  0},
	        {4,  2,  8,  6,  5,  7,  3,  9,  0,  1},
	        {2,  7,  9,  3,  8,  0,  6,  4,  1,  5},
	        {7,  0,  4,  6,  9,  1,  3,  2,  5,  8}};
	        int[] INV_TABLE = new int[]
	        {0,  4,  3,  2,  1,  5,  6,  7,  8,  9};
	        //String code = Long.toString(X);
	        int checksum = 0;
	        for (int i = 0; i < code.length(); i++) {
	            int idx = code.length() - (i + 1); int num = Character.getNumericValue(code.charAt(idx));int pos = i + 1; //  includesCheckDigit ? i : i + 1;   --> includesCheckDigit = false;
	            checksum = D_TABLE[checksum][P_TABLE[pos % 8][num]];
	        }
	        return INV_TABLE[checksum];
	    }

	    int[] sBox = new int[256];int arc4Counter1 = 0;int arc4Counter2 = 0;
	    String[] hexDigits = new String[]{"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};
	    
	    public void initializeArc4SBox( String key ) {
	        int[] kBox = new int[256];arc4Counter1 = 0;arc4Counter2 = 0;
	        if ( key.length() == 0 )
	            key = "0";
	        int j = 0;
	        for (int i=0; i<256; i++) {
	            kBox[i] = (int)key.charAt(j);
	            j = (j+1)%key.length();
	            sBox[i] = i;
	        }
	        j = 0;
	        for (int i=0; i<256; i++) {
	            j = (j+sBox[i]+kBox[i]) % 256;int temp = sBox[i];sBox[i] = sBox[j];sBox[j] = temp;
	        }

	    }
	    
	    public int arc4GetNextByte() {
	        arc4Counter1 = (arc4Counter1+1) % 256;arc4Counter2 = (arc4Counter2 + sBox[arc4Counter1]) % 256;int si = sBox[ arc4Counter1 ];
	        int sj = sBox[ arc4Counter2 ];sBox[ arc4Counter1 ] = sj;sBox[ arc4Counter2 ] = si;int t = (si+sj) % 256;
	        return sBox[t];
	    }
	    
	    public String arc4EncryptByte( int plaintextByte ) {
	        int ciphertextByte = plaintextByte ^ arc4GetNextByte();
	        String str = hexDigits[(int) Math.floor((ciphertextByte/16)&0x0F) ];
	        str += hexDigits[ ciphertextByte & 0x0F ];
	        return str;
	    }
	    
	    public String arc4( String S, String key ) {
	        initializeArc4SBox( key );String C = "";
	        for (int j = 0 ; j < S.length() ; j++) {
	            C = C + arc4EncryptByte( (int)S.charAt(j) );
	        }
	        return C ;
	    }
	    
	    public double round(double num, int dec ) {
	        double aux = num * Math.pow( 10, dec);
	        return  Math.round(aux) / Math.pow( 10, dec);
	    }
}
